/**
 * Project Name:kany-project-blog-web
 * File Name:AuthenticationResource.java
 * Package Name:me.kany.project.blog.resource
 * Date:2016年9月21日上午11:53:57
 * Copyright (c) 2016, Jason.Wang All Rights Reserved.
 */
package me.kany.project.blog.resource;

import java.util.Calendar;
import java.util.Date;

import javax.servlet.ServletContext;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import me.kany.project.blog.resource.model.Token;
import me.kany.project.blog.resource.model.User;
import me.kany.utils.token.KeyUtil;
import me.kany.utils.token.TokenUtil;

/**
 * ClassName:AuthenticationResource<br/>
 * Function: 权限处理<br/>
 * Date:2016年9月21日上午11:53:57<br/>
 * 
 * @author Jason.Wang
 * @version 1.0
 * @since JDK1.7
 * @see
 */
@Provider
@Path("/authentication")
public class AuthenticationResource {
	private final static Logger logger = LoggerFactory.getLogger(AuthenticationResource.class.getCanonicalName());
	
	@Context
    private ServletContext context;
	
	/**
	 * 
	 * authenticateUser: 用户权限设置. <br/>
	 *
	 * @author Jason.Wang
	 * @version 1.0
	 * @param username
	 * @param password
	 * @return
	 * @since JDK1.7
	 *
	 */
	@POST
	@Produces("application/json")
	@Consumes("application/x-www-form-urlencoded")
	public Response authenticateUser(@NotNull @FormParam("username") String username,@NotNull @FormParam("password") String password) {
		// 设置这个token的生命时间
		Date expiry = getExpiryDate(30 * 24 * 60);// 30天的有效日期
		// 验证账号密码是否正确
		User user = authenticate(username, password);
		// 使用Token工具类得到token，生成的策略是利用用户的姓名，到期时间，和私钥
		// 我这里使用的时Key key =MacProvider.generateKey(SignatureAlgorithm.HS512);
		// HS512签名算法，必须保存生成的这个key到硬盘上，不然下次会出错,因为是hash算法，所以会变
		// 这个私钥可以理解为一把锁孔，可以依据这个锁孔来生成钥匙也就是token，但要进入这个门必须要匹配这个锁孔
		String jwtString = TokenUtil.getJWTString(username, user.getRoles(), user.getVersion(), expiry, KeyUtil.getKey(context));
		// 这是token的实体化类，用来返回给用户
		Token token = new Token();
		// 设置生产的jwtString
		token.setAuthToken(jwtString);
		token.setExpires(expiry);
		return Response.ok(token).build();
	}

	/**
	 * 
	 * getExpiryDate: 获取当前的失效时间. <br/>
	 *
	 * @author Jason.Wang
	 * @version 1.0
	 * @param minutes
	 * @return
	 * @since JDK1.7
	 *
	 */
	private Date getExpiryDate(int minutes) {
		// 根据当前日期，来得到到期日期
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, minutes);
		return calendar.getTime();
	}

	/**
	 * 
	 * authenticate: 在这个方法中实现验证用户账号密码，如果错误就抛出未验证信息，如果正确就返回一个用户. <br/>
	 *
	 * @author Jason.Wang
	 * @version 1.0
	 * @param username
	 * @param password
	 * @return
	 * @throws NotAuthorizedException
	 * @since JDK1.7
	 *
	 */
	private User authenticate(String username, String password) throws NotAuthorizedException {
		User user = null;
		// 如果当前的用户和密码都存在
		if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
			/**
			 * 这里可以开始连接数据库获取信息，或者在这里获取Redis的配置信息
			 */
			user = new User();
			user.setId(1L);
			user.setUsername("admin");
			user.setHashedPassword("admins");
			user.setRoles(new String[] { "user" });
			user.setEmail("kzone.wang@gmail.com");
		}
		if (user == null) {
			logger.info("Invalid username '" + username + "' ");
			throw new NotAuthorizedException("Invalid username '" + username + "' ");
		}
		// we need to actually test the Hash not the password, we should never store the password in the database.
		if (user.getHashedPassword().equals(password)) {
			logger.info("USER AUTHENTICATED");
		} else {
			logger.info("USER NOT AUTHENTICATED");
			throw new NotAuthorizedException("Invalid username or password");
		}
		return user;
	}
}
